﻿using System;
using System.Collections.Generic;
using Object = UnityEngine.Object;

namespace MLog.Core {
    public class LoggerEvent {
        public LogLevel Level { set; get; }
        public Exception Exception { set; get; }
        public Object Context { set; get; }
        public string Message { set; get; }
        public object[] Args { set; get; }
        public string ThreadName { set; get; }
        public DateTime Time { set; get; }
        public ILogger Source { set; get; }

        public static LoggerEvent Obtain(ILogger source, string threadName, DateTime time,
            LogLevel level, Exception exception = null, Object context = null, string message = null,
            object[] args = null) {
            var loggerEvent = EventPool.Intance.Get() ?? new LoggerEvent();
            loggerEvent.Source     = source;
            loggerEvent.ThreadName = threadName;
            loggerEvent.Time       = time;
            loggerEvent.Level      = level;
            loggerEvent.Exception  = exception;
            loggerEvent.Context    = context;
            loggerEvent.Message    = message;
            loggerEvent.Args       = args;
            return loggerEvent;
        }

        public void Recycle() {
            Source     = null;
            ThreadName = null;
            Time       = DateTime.MinValue;
            Exception  = null;
            Context    = null;
            Message    = null;
            Args       = null;
            EventPool.Intance.Put(this);
        }

        public LoggerEvent Copy() {
            var copy = new LoggerEvent();
            copy.Source     = Source;
            copy.ThreadName = ThreadName;
            copy.Time       = Time;
            copy.Exception  = Exception;
            copy.Context    = Context;
            copy.Message    = Message;
            copy.Args       = Args;
            return copy;
        }

        private class EventPool {
            public static readonly EventPool Intance = new EventPool(64);

            private readonly Queue<LoggerEvent> _events;

            private readonly int _maxCapacity;

            private EventPool(int maxCapacity) {
                _maxCapacity = maxCapacity;
                _events      = new Queue<LoggerEvent>(maxCapacity);
            }

            public LoggerEvent Get() {
                return _events.Count > 0 ? _events.Dequeue() : null;
            }

            public void Put(LoggerEvent @event) {
                if (_events.Count < _maxCapacity) _events.Enqueue(@event);
            }
        }
    }
}